﻿
Public MustInherit Class CSearchReplaceBase
    Public MustOverride Function Execute(ByVal strSrc_i As String) As String
    Public MustOverride ReadOnly Property Rank As Int32

    Public Shared Function TransformationCllToArr(ByVal cll_i As NSCllG.IEnumerable(Of CSearchReplaceBase)) As CSearchReplaceBase()
        If cll_i Is Nothing Then
            Return New CSearchReplaceSubsting() {}
        End If

        Dim cllLst As New NSCllG.LinkedList(Of CSearchReplaceBase)

        For Each objIt As CSearchReplaceBase In cll_i
            Dim objLstNode = cllLst.Last

            Do Until objLstNode Is Nothing
                If objLstNode.Value.Rank <= objIt.Rank Then
                    cllLst.AddAfter(objLstNode, objIt)
                    Exit Do
                End If

                objLstNode = objLstNode.Previous
            Loop

            If objLstNode Is Nothing Then
                cllLst.AddLast(objIt)
            End If
        Next

        Dim cllRetArr() As CSearchReplaceBase = Nothing
        Array.Resize(cllRetArr, cllLst.Count)
        cllLst.CopyTo(cllRetArr, 0)
        Return cllRetArr
    End Function
End Class

Public NotInheritable Class CSearchReplaceSubsting
    Inherits CSearchReplaceBase

    Private mstrSearch As String
    Private mstrReplaceTo As String
    Private menmComparisonType As StringComparison
    Private mnumRank As Int32
    Private mnumBufferLenFactor As Int32

    Public ReadOnly Property Search As String
        Get
            Return mstrSearch
        End Get
    End Property

    Public ReadOnly Property ReplaceTo As String
        Get
            Return mstrReplaceTo
        End Get
    End Property

    Public Sub New(ByVal numRank_i As Int32, ByVal strSearch_i As String, ByVal strReplace_i As String)
        MyClass.New(numRank_i, strSearch_i, strReplace_i, StringComparison.Ordinal)
    End Sub

    Public Sub New(ByVal numRank_i As Int32, ByVal strSearch_i As String, ByVal strReplace_i As String, ByVal enmComparisonType_i As StringComparison)
        If String.IsNullOrEmpty(strSearch_i) Then
            Throw New ArgumentNullException("strSearch_i")
        End If

        If strSearch_i = strReplace_i Then
            Throw New ArgumentNullException("strReplace_i", "strReplace_i can not be equal strSearch_i.")
        End If

        mstrSearch = strSearch_i

        If strReplace_i Is Nothing Then
            mstrReplaceTo = String.Empty
        Else
            mstrReplaceTo = strReplace_i
        End If

        menmComparisonType = enmComparisonType_i
        mnumRank = numRank_i

        Dim num = mstrReplaceTo.Length - mstrSearch.Length

        If num <= 0 Then
            mnumBufferLenFactor = 1
        Else
            mnumBufferLenFactor = num
        End If
    End Sub

    Public Overrides Function Execute(strSrc_i As String) As String
        Dim numBufferLen = Int32.MaxValue \ mnumBufferLenFactor

        If numBufferLen >= strSrc_i.Length Then
            numBufferLen = strSrc_i.Length * mnumBufferLenFactor
        End If

        Dim objSB = New Text.StringBuilder(strSrc_i, numBufferLen)
        Dim numIdx = strSrc_i.LastIndexOf(mstrSearch, menmComparisonType)

        Do Until numIdx < 0
            objSB.Remove(numIdx, mstrSearch.Length).Insert(numIdx, mstrReplaceTo)
            numIdx = strSrc_i.LastIndexOf(mstrSearch, numIdx - 1, menmComparisonType)
        Loop

        Return objSB.ToString()
    End Function

    Public Overrides ReadOnly Property Rank As Integer
        Get
            Return mnumRank
        End Get
    End Property
End Class

Public NotInheritable Class CSearchReplaceRegExpr
    Inherits CSearchReplaceBase

    Private mobjREMain As NSRegExp.Regex
    Private mstrReplaceTo As String
    Private mnumRank As Int32

    Public ReadOnly Property SearchRegExpr As NSRegExp.Regex
        Get
            Return mobjREMain
        End Get
    End Property

    Public ReadOnly Property ReplaceTo As String
        Get
            Return mstrReplaceTo
        End Get
    End Property

    Public Sub New(ByVal numRank_i As Int32, ByVal objRegExpr_i As NSRegExp.Regex, ByVal strReplace_i As String)
        If objRegExpr_i Is Nothing Then
            Throw New ArgumentNullException("objRegExpr_i")
        End If

        If strReplace_i Is Nothing Then
            Throw New ArgumentNullException("strReplace_i")
        End If

        mobjREMain = New NSRegExp.Regex(objRegExpr_i.ToString(), (NSRegExp.RegexOptions.Compiled Or objRegExpr_i.Options))
        mstrReplaceTo = strReplace_i
        mnumRank = numRank_i
    End Sub

    Public Sub New(ByVal numRank_i As Int32, ByVal strSearch_i As String, ByVal strReplace_i As String, ByVal enmREOpt_i As NSRegExp.RegexOptions)
        If strReplace_i Is Nothing Then
            Throw New ArgumentNullException("strReplace_i")
        End If

        mobjREMain = New NSRegExp.Regex(strSearch_i, (NSRegExp.RegexOptions.Compiled Or enmREOpt_i))
        mstrReplaceTo = strReplace_i
        mnumRank = numRank_i
    End Sub

    Public Overrides Function Execute(strSrc_i As String) As String
        Dim objStr As New Text.StringBuilder(strSrc_i)
        Dim cllRE = mobjREMain.Matches(strSrc_i)

        For k As Int32 = cllRE.Count - 1 To 0 Step -1
            Dim objREMIt = cllRE.Item(k)
            objStr.Remove(objREMIt.Index, objREMIt.Length).Insert(objREMIt.Index, mstrReplaceTo)
        Next

        Return objStr.ToString()
    End Function

    Public Overrides ReadOnly Property Rank As Integer
        Get
            Return mnumRank
        End Get
    End Property
End Class
